/*
 * This code was created by Jeff Molofee '99 
 * (ported to Linux/SDL by Ti Leggett '01)
 *
 * If you've found this code useful, please let me know.
 *
 * Visit Jeff at http://nehe.gamedev.net/
 * 
 * or for port-specific comments, questions, bugreports etc. 
 * email to leggett@eecs.tulane.edu
 */
 
#include <stdio.h>
#include <stdlib.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <SDL/SDL.h>
#include <SDL/SDL_image.h>

/* screen width, height, and bit depth */
#define SCREEN_WIDTH  640
#define SCREEN_HEIGHT 480
#define SCREEN_BPP     16

/* Setup our booleans */
#define TRUE  1
#define FALSE 0

/* Max number of particles */
#define MAX_PARTICLES 1000

/* This is our SDL surface */
SDL_Surface *surface;

int rainbow = TRUE;    /* Toggle rainbow effect                              */

float slowdown = 2.0f; /* Slow Down Particles                                */
float xspeed;          /* Base X Speed (To Allow Keyboard Direction Of Tail) */
float yspeed;          /* Base Y Speed (To Allow Keyboard Direction Of Tail) */
float zoom = 1.0f;   /* Used To Zoom Out                                   */

GLuint loop;           /* Misc Loop Variable                                 */
GLuint col = 0;        /* Current Color Selection                            */
GLuint delay=25;          /* Rainbow Effect Delay                               */
GLuint ptexture[1];     /* Storage For Our Particle Texture                   */

/* Create our particle structure */
typedef struct
{
    int   active; /* Active (Yes/No) */
    float life;   /* Particle Life   */
    float fade;   /* Fade Speed      */

    float r;      /* Red Value       */
    float g;      /* Green Value     */
    float b;      /* Blue Value      */

    float x;      /* X Position      */
    float y;      /* Y Position      */
    float z;      /* Z Position      */

    float xi;     /* X Direction     */
    float yi;     /* Y Direction     */
    float zi;     /* Z Direction     */

    float xg;     /* X Gravity       */
    float yg;     /* Y Gravity       */
    float zg;     /* Z Gravity       */
} particle;

/* Rainbow of colors */
static GLfloat colors[12][3] =
{
        { 1.0f,  0.5f,  0.5f},
	{ 1.0f,  0.75f, 0.5f},
	{ 1.0f,  1.0f,  0.5f},
	{ 0.75f, 1.0f,  0.5f},
        { 0.5f,  1.0f,  0.5f},
	{ 0.5f,  1.0f,  0.75f},
	{ 0.5f,  1.0f,  1.0f},
	{ 0.5f,  0.75f, 1.0f},
        { 0.5f,  0.5f,  1.0f},
	{ 0.75f, 0.5f,  1.0f},
	{ 1.0f,  0.5f,  1.0f},
	{ 1.0f,  0.5f,  0.75f}
};

/* Our beloved array of particles */
particle particles[MAX_PARTICLES];



/* function to load in bitmap as a GL texture */
int LoadGLTextures( )
{
    /* Status indicator */
    int Status = FALSE;

    /* Create storage space for the texture */
    SDL_Surface *TextureImage[1]; 

    /* Load The Bitmap, Check For Errors, If Bitmap's Not Found Quit */
    if ( ( TextureImage[0] = IMG_Load( "data/particle.png" ) ) )
        {

	    /* Set the status to true */
	    Status = TRUE;

	    /* Create The Texture */
	    glGenTextures( 1, &ptexture[0] );

	    /* Typical Texture Generation Using Data From The Bitmap */
	    glBindTexture( GL_TEXTURE_2D, ptexture[0] );

	    /* Generate The Texture */
	    glTexImage2D( GL_TEXTURE_2D, 0, 3, TextureImage[0]->w,
			  TextureImage[0]->h, 0, GL_RGB,
			  GL_UNSIGNED_BYTE, TextureImage[0]->pixels );

	    /* Linear Filtering */
	    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
	    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
        }

    /* Free up any memory we may have used */
    if ( TextureImage[0] )
	    SDL_FreeSurface( TextureImage[0] );

    return Status;
}




/* function to reset one particle to initial state */
/* NOTE: I added this function to replace doing the same thing in several
 * places and to also make it easy to move the pressing of numpad keys
 * 2, 4, 6, and 8 into handleKeyPress function.
 */
void ResetParticle( int num, int color, float xDir, float yDir, float zDir )
{
    /* Make the particels active */
    particles[num].active = TRUE;
    /* Give the particles life */
    particles[num].life = 5.0f;
    /* Random Fade Speed */
    particles[num].fade = ( float )( rand( ) %100 ) / 1000.0f + 0.003f;
    /* Select Red Rainbow Color */
    particles[num].r = colors[color][0];
    /* Select Green Rainbow Color */
    particles[num].g = colors[color][1];
    /* Select Blue Rainbow Color */
    particles[num].b = colors[color][2];
    /* Set the position on the X axis */
    particles[num].x = 0.0f;
    /* Set the position on the Y axis */
    particles[num].y = 0.0f;
    /* Set the position on the Z axis */
    particles[num].z = -2.0f;
    /* Random Speed On X Axis */
    particles[num].xi = xDir;
    /* Random Speed On Y Axi */
    particles[num].yi = yDir;
    /* Random Speed On Z Axis */
    particles[num].zi = zDir;
    /* Set Horizontal Pull To Zero */
    particles[num].xg = 0.0f;
    /* Set Vertical Pull Downward */
    particles[num].yg = 0.0f;
    /* Set Pull On Z Axis To Zero */
    particles[num].zg = -0.10f;

    return;
}



/* general OpenGL initialization function */
int initParticles( void )
{

    LoadGLTextures();
    /* Enable Texture Mapping */
    glEnable( GL_TEXTURE_2D );
    /* Select Our Texture */
    glBindTexture( GL_TEXTURE_2D, ptexture[0] );

    /* Reset all the particles */
    for ( loop = 0; loop < MAX_PARTICLES; loop++ )
	{
	    int color = ( loop + 1 ) / ( MAX_PARTICLES / 12 );
	    float xi, yi, zi;
	    xi =  ( float )( ( rand( ) % 50 ) - 26.0f ) * 10.0f;
	    yi = zi = ( float )( ( rand( ) % 50 ) - 25.0f ) * 10.0f;

	    ResetParticle( loop, color, xi, yi, zi );
        }

    return( TRUE );
}

/* Here goes our drawing code */
int drawParticles( void )
{
    /* These are to calculate our fps */
    static GLint T0     = 0;
    static GLint Frames = 0;

    /* Clear The Screen And The Depth Buffer */

    /* Modify each of the particles */
glPushMatrix();
glBindTexture( GL_TEXTURE_2D, ptexture[0] );
    glEnable( GL_BLEND );
    glDisable(GL_LIGHTING); 
    /* Type Of Blending To Perform */
    glBlendFunc( GL_SRC_ALPHA, GL_ONE );
    if ( rainbow && ( delay > 25 ) )
		col = ( ++col ) % 12;

    for ( loop = 0; loop < MAX_PARTICLES; loop++ )
	{
	    if ( particles[loop].active )
		{
		    /* Grab Our Particle X Position */
		    float x = particles[loop].x;
		    /* Grab Our Particle Y Position */
		    float y = particles[loop].y;
		    /* Particle Z Position + Zoom */
		    float z = particles[loop].z + zoom;

		    /* Draw The Particle Using Our RGB Values,
		     * Fade The Particle Based On It's Life
		     */
		    glColor4f( particles[loop].r,
			       particles[loop].g,
			       particles[loop].b,
			       particles[loop].life );

		    /* Build Quad From A Triangle Strip */
		    glBegin( GL_TRIANGLE_STRIP );
		      /* Top Right */
		      glTexCoord2d( 1, 1 );
		      glVertex3f( x + 0.5f, y + 0.5f, z );
		      /* Top Left */
		      glTexCoord2d( 0, 1 );
		      glVertex3f( x - 0.5f, y + 0.5f, z );
		      /* Bottom Right */
		      glTexCoord2d( 1, 0 );
		      glVertex3f( x + 0.5f, y - 0.5f, z );
		      /* Bottom Left */
		      glTexCoord2d( 0, 0 );
		      glVertex3f( x - 0.5f, y - 0.5f, z );
		    glEnd( );

		    /* Move On The X Axis By X Speed */
		    particles[loop].x += particles[loop].xi /
			( slowdown * 1000 );
		    /* Move On The Y Axis By Y Speed */
		    particles[loop].y += particles[loop].yi /
			( slowdown * 1000 );
		    /* Move On The Z Axis By Z Speed */
		    particles[loop].z += particles[loop].zi /
			( slowdown * 1000 );

		    /* Take Pull On X Axis Into Account */
		    particles[loop].xi += particles[loop].xg;
		    /* Take Pull On Y Axis Into Account */
		    particles[loop].yi += particles[loop].yg;
		    /* Take Pull On Z Axis Into Account */
		    particles[loop].zi += particles[loop].zg;

		    /* Reduce Particles Life By 'Fade' */
		    particles[loop].life -= particles[loop].fade;

		    /* If the particle dies, revive it */
		    if ( particles[loop].life < 0.0f )
			{
			    float xi, yi, zi;
			    xi = xspeed +
				( float )( ( rand( ) % 60 ) - 32.0f );
			    yi = yspeed +
				( float)( ( rand( ) % 60 ) - 30.0f );
			    zi = ( float )( ( rand( ) % 60 ) - 30.0f );
			    ResetParticle( loop, col, xi, yi, zi );
                        }
		}
	}

	delay++;

glDisable( GL_BLEND );
glPopMatrix();
glBindTexture( GL_TEXTURE_2D,NULL );
    return( TRUE );
}

void ExplotarParticulas(){
	    for ( loop = 0; loop < MAX_PARTICLES; loop++ )
		{
		   int color = ( loop + 1 ) / ( MAX_PARTICLES / 12 );
		   float xi, yi, zi;
		   xi = ( float )( ( rand( ) % 50 ) - 26.0f ) * 10.0f;
		   yi = zi = ( float )( ( rand( ) % 50 ) - 25.0f ) * 10.0f;

		   ResetParticle( loop, color, xi, yi, zi );
		}
}
